package com.spa.domain.service;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.RandomUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.spa.application.command.shop.MassagistAddCommand;
import com.spa.application.command.shop.MassagistDelCommand;
import com.spa.application.command.shop.MassagistEditCommand;
import com.spa.application.dto.massagist.MassagistFinanceDetailDTO;
import com.spa.application.dto.massagist.MassagistIncomeDetailDTO;
import com.spa.application.query.admin.MassagitsPageQuery;
import com.spa.domain.entity.MassageServiceEntity;
import com.spa.domain.entity.Massagist;
import com.spa.domain.entity.OrderExt;
import com.spa.domain.entity.OrderInfo;
import com.spa.domain.entity.PlatformSysUserEntity;
import com.spa.domain.entity.Profit;
import com.spa.domain.entity.Shop;
import com.spa.infrastructure.enums.dict.base.WhetherTypeEnum;
import com.spa.infrastructure.enums.dict.massagist.MassagistStatusEnum;
import com.spa.infrastructure.enums.dict.massagist.MassagistTypeEnum;
import com.spa.infrastructure.enums.dict.order.OrderOperStatusEnum;
import com.spa.infrastructure.enums.dict.order.OrderStatusEnum;
import com.spa.infrastructure.exception.SpaException;
import com.spa.infrastructure.mapper.MassageServiceMapperStruct;
import com.spa.infrastructure.mapper.MassagistMapperStruct;
import com.spa.infrastructure.repository.condition.MassageRefCondition;
import com.spa.infrastructure.repository.condition.MassageServiceCondition;
import com.spa.infrastructure.repository.condition.MassagistCondition;
import com.spa.infrastructure.repository.condition.MassagistEvaluateCondition;
import com.spa.infrastructure.repository.condition.OrderInfoCondition;
import com.spa.infrastructure.repository.condition.ShopCondition;
import com.spa.infrastructure.repository.condition.UserCollectionRefCondition;
import com.spa.infrastructure.repository.po.MassageRefPO;
import com.spa.infrastructure.repository.po.MassageServicePO;
import com.spa.infrastructure.repository.po.MassagistEvaluatePO;
import com.spa.infrastructure.repository.po.MassagistPO;
import com.spa.infrastructure.repository.po.ShopPO;
import com.spa.infrastructure.repository.po.UserCollectionRefPO;
import com.spa.infrastructure.repository.service.MassageRefRepositoryService;
import com.spa.infrastructure.repository.service.MassageServiceRepositoryService;
import com.spa.infrastructure.repository.service.MassagistEvaluateRepositoryService;
import com.spa.infrastructure.repository.service.MassagistRepositoryService;
import com.spa.infrastructure.repository.service.ShopRepositoryService;
import com.spa.infrastructure.repository.service.UserCollectionRepositoryService;
import com.spa.infrastructure.util.SessionUtil;
import com.spa.infrastructure.util.StringUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.function.Function;
import java.util.stream.Collectors;

@Service
@Slf4j
public class MassagistService {

    @Resource
    private MassagistRepositoryService massagistRepositoryService;

    @Resource
    private ShopRepositoryService shopRepositoryService;

    @Resource
    private MassageRefRepositoryService massageRefRepositoryService;

    @Resource
    private PlatformSysUserService sysUserService;

    @Autowired
    private MassageServiceRepositoryService massageServiceRepositoryService;

    @Resource
    private ShopService shopService;

    @Resource
    private UserCollectionRepositoryService userCollectionRepositoryService;
    @Resource
    private UserInfoService userInfoService;

    @Resource
    private OrderService orderService;

    @Resource
    private MassagistEvaluateRepositoryService massagistEvaluateRepositoryService;

    @Autowired
    private MassagistOnoffService massagistOnoffService;

    @Autowired
    private ProfitService profitService;
    @Autowired
    private MassagistService massagistService;
    @Autowired
    private RuleService ruleService;


    /**
     * 获取技师详情
     *
     * @author: lig
     * @date: 2023/12/6
     */
    public Massagist infoById(Long id) {
        MassagistPO m = massagistRepositoryService.getById(id);
        Massagist massagist = MassagistMapperStruct.INSTANCE.po2Entity(m);
        if (BeanUtil.isNotEmpty(m)) {
            Shop shop = shopService.getInfoById(massagist.getShopId());
            massagist.setShopId(shop.getId());
            massagist.setShopName(shop.getName());
            massagist.setFollowCount(userCollectionRepositoryService.countCollectionByMassagistId(m.getId()) + massagist.getFollowCount());

            //评分
            if (Convert.toDouble(massagist.getScore(), 0d) <= 0) {
                massagist.setScore("5.0");
            } else {
                massagist.setScore(Convert.toStr(massagist.getScore(), "5.0"));
            }
        }
        return massagist;
    }

    public Massagist getMassagistInfoByUserId() {
        Long userId = SessionUtil.getUser().getExtUserId();
        if (ObjectUtil.isNull(userId)) {
            throw new SpaException("无效的登录用户");
        }
        MassagistPO m = massagistRepositoryService.getOneById(userId);
        return MassagistMapperStruct.INSTANCE.po2Entity(m);
    }

    public boolean optionMyStatus(Massagist massagist) {
        MassagistPO massagistPO = new MassagistPO();
        massagistPO.setId(massagist.getId());
        massagistPO.setStatus(massagist.getStatus());
        massagistPO.setAppointmentTime(massagist.getAppointmentTime());
        massagistPO.setLat(massagist.getLat());
        massagistPO.setLon(massagist.getLon());
        return massagistRepositoryService.updateMassagitByCondition(massagistPO);
    }

    public boolean optionMyStatus(Long messagistId, Integer status) {
        MassagistPO massagistPO = new MassagistPO();
        massagistPO.setId(messagistId);
        massagistPO.setStatus(status);
        return massagistRepositoryService.updateMassagitByCondition(massagistPO);
    }

    public boolean massagistExists(MassagistCondition condition) {
        return massagistRepositoryService.massagistExistsByStatus(condition);
    }

    public Page<Massagist> page(MassagistCondition condition) {
        Page<MassagistPO> page = massagistRepositoryService.pageJoinShopMassagistRef(condition);
        //根据技师ID查询出技师服务关系
        List<Long> massagistIds = page.getRecords().stream().map(MassagistPO::getId).toList();
        MassageRefCondition massageRefCondition = new MassageRefCondition();
        massageRefCondition.setMassagistIds(massagistIds);
        List<MassageRefPO> massageRefs = massageRefRepositoryService.listMassageRefByCondition(massageRefCondition);
        Map<Long, List<MassageRefPO>> map = massageRefs.stream().collect(Collectors.groupingBy(MassageRefPO::getMassagistId));
        //根据服务ID查询出对应的服务
        List<Long> serviceIds = massageRefs.stream().map(MassageRefPO::getServiceId).toList();
        MassageServiceCondition massageServiceCondition = new MassageServiceCondition();
        massageServiceCondition.setServiceIds(serviceIds);
        massageServiceCondition.setIsDel(WhetherTypeEnum.$0.getCode());
        List<MassageServicePO> messageServices = massageServiceRepositoryService.getMessageServicePOListByCondition(massageServiceCondition);
        List<MassageServiceEntity> messageServiceList = MassageServiceMapperStruct.INSTANCE.po2Entity4List(messageServices);
        //给技师赋值所拥有的服务
        Page<Massagist> massagistPage = MassagistMapperStruct.INSTANCE.po2Entity4Page(page);

        massagistPage.getRecords().forEach(massagist -> {
            List<MassageRefPO> massageRefPOS = map.get(massagist.getId());
            if (CollectionUtil.isNotEmpty(massageRefPOS)) {
                List<Long> ids = massageRefPOS.stream().map(MassageRefPO::getServiceId).toList();
                List<MassageServiceEntity> messageServiceS =
                        messageServiceList.stream().filter(messageService -> ids.contains(messageService.getId())).toList();
                massagist.setMassageServiceEntities(messageServiceS);
            }

        });
        return massagistPage;
    }

    /**
     * 通过门店Id查询门店下所有的技师
     *
     * @param shopId 门店Id
     * @return 技师列表
     */
    public List<Massagist> listByShopId(Long shopId) {
        MassagistCondition condition = new MassagistCondition();
        condition.setShopId(shopId);
        List<MassagistPO> massagistPOList = massagistRepositoryService.list(condition);
        return MassagistMapperStruct.INSTANCE.po2Entity4List(massagistPOList);
    }

    /**
     * 根据条件查询技师列表（用户端使用）
     * &#064;author:  lig
     * &#064;date:  2024/1/27
     */
    public List<Massagist> memberList(MassagistCondition condition) {
        if (ObjectUtil.isNotEmpty(condition.getCityId())) {
            //获取城市下的所有门店   edit 2024-03-14 lig 只获取上架的门店
            ShopCondition shopCondition = new ShopCondition();
            shopCondition.setCityId(condition.getCityId());
            shopCondition.setIsDel(WhetherTypeEnum.$0.getCode());
            List<Shop> shop = shopService.getListByCondition(shopCondition);
            if (CollUtil.isEmpty(shop)) {
                return new ArrayList<>();
            }
            condition.setShopIds(shop.stream().map(Shop::getId).toList());
        }
        List<Massagist> massagistList = MassagistMapperStruct.INSTANCE.po2Entity4List(massagistRepositoryService.list(condition));
        if (CollUtil.isEmpty(massagistList)) {
            return new ArrayList<>();
        }
        //用户收藏相关
        List<Long> umcIdList = userInfoService.myUserCollectionIds();
        List<Map<String, Object>> mapList = userCollectionRepositoryService.countByMassagistIds(massagistList.stream().map(Massagist::getId).toList());
        Map<String, Object> longIntegerMap = new HashMap<>();
        mapList.forEach(l -> longIntegerMap.put(l.get("massagist_id").toString(), l.get("count")));

        Map<Long, Shop> map = shopService.groupById(shopService.listShopByIds(massagistList.stream().map(Massagist::getShopId).toList()));
        //构造需要参数
        massagistList.forEach(m -> {
            //评分
            if (Convert.toDouble(m.getScore(), 0d) <= 0) {
                m.setScore("5.0");
            } else {
                m.setScore(Convert.toStr(m.getScore(), "5.0"));
            }
            //设置用户是否收藏
            if (umcIdList.stream().anyMatch(umc -> umc.equals(m.getId()))) {
                m.setUserCollectionFlag(true);
            }
            //收藏数 收藏数量100-300随机整数+实际
            m.setFollowCount(Convert.toLong(longIntegerMap.get(String.valueOf(m.getId())), 0L) + m.getFollowCount());
            //归属门店
            if (ObjectUtil.isNotEmpty(map.get(m.getShopId()))) {
                m.setShopName(map.get(m.getShopId()).getName());
            }
        });
        return massagistList;
    }


    /**
     * 获取技师分页列表
     * 2024-01-10 增加 收藏标识
     *
     * @author: lig
     * @date: 2023/12/9
     */
    public Page<Massagist> massagistPage(MassagistCondition condition) {

        if (ObjectUtil.isNotEmpty(condition.getServiceId())) {
            MassageRefCondition refCondition = new MassageRefCondition();
            refCondition.setServiceId(condition.getServiceId());
            //获取指定项目的技师ID集
            List<MassageRefPO> massagistIds = massageRefRepositoryService.refList(refCondition);
            if (CollUtil.isNotEmpty(massagistIds)) {
                condition.setMassagistIds(massagistIds.stream().map(MassageRefPO::getMassagistId).toList());
            }
        }
        if (ObjectUtil.isNotEmpty(condition.getCityId())) {
            //获取城市门店
            List<Shop> shop = shopService.getShopByCitiesId(condition.getCityId());
            if (CollUtil.isNotEmpty(shop)) {
                condition.setShopIds(shop.stream().map(Shop::getId).toList());
            }
        }

        Page<MassagistPO> page = massagistRepositoryService.page(condition);
        Page<Massagist> entityPage = MassagistMapperStruct.INSTANCE.po2Entity4Page(page);

        //add 用户收藏相关 lig 2024-01-10
        List<Long> umcIdList = userInfoService.myUserCollectionIds();

        entityPage.getRecords().stream().forEach(a -> {
            //获取归属门店
            Shop shop = shopService.getInfoById(a.getShopId());
            a.setShopId(shop.getId());
            a.setShopName(shop.getName());

            //用户是否收藏  add 用户收藏相关 lig 2024-01-10
            if (umcIdList.stream().filter(umc -> umc.equals(a.getId())).count() > 0) {
                a.setUserCollectionFlag(true);
            }
            //获取收藏数
            a.setFollowCount(userCollectionRepositoryService.countCollectionByMassagistId(a.getId()) + a.getFollowCount());


            //评分
            if (Convert.toDouble(a.getScore(), 0d) <= 0) {
                a.setScore("5.0");
            } else {
                a.setScore(Convert.toStr(a.getScore(), "5.0"));
            }

        });
        return entityPage;
    }

    /**
     * 添加技师
     *
     * @author: lig
     * @date: 2023/12/6
     */
    @Transactional
    public Long addMassagistInfo(MassagistAddCommand command) {
        if (StringUtils.isNotEmpty(command.getLifePhoto())) {
            String[] s = command.getLifePhoto().split(",");
            if (s.length > 5) {
                throw new SpaException("图片最多上传5张");
            }
        }
        MassagistPO massagistPO = getMassagistPO(command);
        command.getServiceList().forEach(serviceId -> addMassageRef(serviceId, massagistPO.getId()));
        return massagistPO.getId();
    }

    private void addMassageRef(Long serviceId, Long massagistId) {
        MassageRefPO massageRefPO = new MassageRefPO();
        massageRefPO.setServiceId(serviceId);
        massageRefPO.setMassagistId(massagistId);
        massageRefRepositoryService.addMassageRef(massageRefPO);
    }

    private MassagistPO getMassagistPO(MassagistAddCommand command) {
        MassagistPO massagistPO = MassagistMapperStruct.INSTANCE.command2Po(command);
        massagistPO.setStatus(MassagistStatusEnum.$10.getCode());
        massagistPO.setIsDel(0);
        int random = RandomUtil.randomInt(100, 2000);
        massagistPO.setSelectCount(random);
        int random1 = RandomUtil.randomInt(100, 300);
        massagistPO.setFollowCount(random1);
        massagistRepositoryService.addMassagist(massagistPO);
        return massagistPO;
    }

    private Long getUserId(MassagistAddCommand command) {
        PlatformSysUserEntity sysUserEntity = new PlatformSysUserEntity();
        sysUserEntity.setPhone(command.getPhone());
        return sysUserService.addSysUser(sysUserEntity).getUserId();
    }

    /**
     * 修改技师
     *
     * @author: lig
     * @date: 2023/12/6
     */

    public void editMassagistInfo(MassagistEditCommand command) {
        if (isNotExistById(command.getMassagistId())) {
            return;
        }
        MassagistPO po = MassagistMapperStruct.INSTANCE.command2Po(command);
        editMassagist(po, command.getServiceList());
    }

    @Transactional
    public void editMassagist(MassagistPO po, List<Long> serviceList) {
        if (StringUtils.isNotEmpty(po.getLifePhoto())) {
            String[] s = po.getLifePhoto().split(",");
            if (s.length > 5) {
                throw new SpaException("图片最多上传5张");
            }
        }
        massagistRepositoryService.updateMassagistById(po);
        if (CollectionUtil.isNotEmpty(serviceList)) {
            MassageRefCondition condition = new MassageRefCondition();
            condition.setMassagistId(po.getId());
            massageRefRepositoryService.delMassageRef(condition);
            serviceList.forEach(serviceId -> {
                addMassageRef(serviceId, po.getId());
            });
        }
    }

    @Transactional
    public void delMassagist(MassagistDelCommand command) {
        if (isNotExistById(command.getMassagistId())) {
            return;
        }
        //技师下线
        MassagistPO po = new MassagistPO();
        po.setId(command.getMassagistId());
        po.setIsDel(1);
        massagistRepositoryService.updateMassagistById(po);
        //删除技师服务关系表
        MassageRefCondition massageRefCondition = new MassageRefCondition();
        massageRefCondition.setMassagistId(command.getMassagistId());
        massageRefRepositoryService.delMassageRef(massageRefCondition);
    }

    public boolean isNotExistById(Long id) {
        MassagistPO po = massagistRepositoryService.getOneById(id);
        return !ObjectUtil.isNotNull(po);
    }

    public boolean isExistByPhone(String phone) {
        MassagistCondition condition = new MassagistCondition();
        condition.setPhone(phone);
        MassagistPO po = massagistRepositoryService.getOneByCondition(condition);
        return ObjectUtil.isNotNull(po);
    }

    public Massagist getInfoByMassagistId(Long massagistId) {
        MassagistPO massagist = massagistRepositoryService.getOneById(massagistId);
        if (ObjectUtil.isNull(massagist)) {
            throw new SpaException("缺少有效技师信息");
        }
        return MassagistMapperStruct.INSTANCE.po2Entity(massagist);
    }

    public List<Massagist> getMassagistListByShopId(Long shopId) {
        MassagistCondition massagistCondition = new MassagistCondition();
        massagistCondition.setShopId(shopId);
        return MassagistMapperStruct.INSTANCE.po2Entity4List(massagistRepositoryService.list(massagistCondition));
    }

    /**
     * 查询某个门店下的所有的真实技师
     * @param shopId
     * @return
     */
    public List<Massagist> getRealMassagistListByShopId(Long shopId) {
        MassagistCondition massagistCondition = new MassagistCondition();
        massagistCondition.setShopId(shopId);
        massagistCondition.setTag(MassagistTypeEnum.$10.getCode());
        return MassagistMapperStruct.INSTANCE.po2Entity4List(massagistRepositoryService.list(massagistCondition));
    }

    /**
     * 查询某个城市下的所有的真实技师
     * @param cityId
     * @return
     */
    public List<Massagist> getMassagistListByCityId(long  cityId) {
        ShopCondition shopCondition = new ShopCondition();
        shopCondition.setCityId(cityId);
        shopCondition.setIsDel(WhetherTypeEnum.$0.getCode());
        List<Shop> shop = shopService.getListByCondition(shopCondition);
        List<Long> shopIds = shop.stream().map(Shop::getId).toList();
        MassagistCondition massagistCondition = new MassagistCondition();
        massagistCondition.setShopIds(shopIds);
        massagistCondition.setTag(MassagistTypeEnum.$10.getCode());
        return MassagistMapperStruct.INSTANCE.po2Entity4List(massagistRepositoryService.list(massagistCondition));
    }

    public Massagist massagistInfoByPhone(String phone) {
        MassagistCondition condition = new MassagistCondition();
        condition.setPhone(phone);
        Massagist massagist = MassagistMapperStruct.INSTANCE.po2Entity(massagistRepositoryService.getOneByCondition(condition));
        if (BeanUtil.isNotEmpty(massagist)) {
            //获取门店信息
            Shop shop = shopService.getInfoById(massagist.getShopId());
            if (BeanUtil.isNotEmpty(shop)) {
                massagist.setShopId(shop.getId());
                massagist.setShopName(shop.getName());
            }
        }
        return massagist;
    }

    public boolean editInfo(MassagistPO massagistPO) {
        return massagistRepositoryService.updateMassagitByCondition(massagistPO);
    }

    public Page<Massagist> pageMassagistJoinShop(MassagitsPageQuery query) {
        Page<MassagistPO> page = massagistRepositoryService.pageJoinShopByCondition(MassagistMapperStruct.INSTANCE.pageQuery2condition(query));
        return MassagistMapperStruct.INSTANCE.po2Entity4Page(page);
    }

    public List<Massagist> list(List<Long> ids) {
        MassagistCondition condition = new MassagistCondition();
        condition.setMassagistIds(ids);
        return MassagistMapperStruct.INSTANCE.po2Entity4List(massagistRepositoryService.list(condition));
    }

    public Map<Long, Massagist> groupById(List<Massagist> massagistList) {
        return massagistList.stream().collect(Collectors.toMap(Massagist::getId, Function.identity()));
    }

    public boolean removeMassagitsById(Long massagistId) {
        MassagistPO massagistPO = new MassagistPO();
        massagistPO.setId(massagistId);
        massagistPO.setIsDel(1);
        return massagistRepositoryService.updateMassagitByCondition(massagistPO);
    }

    public List<Long> collectionMassagitsByUserId(Long userId) {

        UserCollectionRefCondition condition = new UserCollectionRefCondition();
        condition.setUserId(userId);
        List<UserCollectionRefPO> poList = userCollectionRepositoryService.listInfo(condition);
        return poList.stream().map(UserCollectionRefPO::getMassagistId).toList();

    }

    public MassagistFinanceDetailDTO getMyFinanceDetails(Long massagistId, String beginDate, String endDate) {
        MassagistIncomeDetailDTO massagistIncomeDetailDTO = getMassagistIncomeDetailDTO(massagistId, beginDate, endDate);
        MassagistFinanceDetailDTO financeDetailDTO = MassagistMapperStruct.INSTANCE.dot2MassagistFinanceDetailDTO(massagistIncomeDetailDTO);
        //在线时长
        financeDetailDTO.setOnlineTime(massagistOnoffService.sumServiceTimeByMassagistId(massagistId, beginDate, endDate));
        return financeDetailDTO;
    }

    public MassagistFinanceDetailDTO getFinanceDetail(Long massagistId, String beginDate, String endDate) {
        MassagistIncomeDetailDTO massagistIncomeDetailDTO = getMassagistIncomeDetailDTO(massagistId, beginDate, endDate);
        MassagistFinanceDetailDTO financeDetailDTO = MassagistMapperStruct.INSTANCE.dot2MassagistFinanceDetailDTO(massagistIncomeDetailDTO);
        return financeDetailDTO;
    }

    public MassagistFinanceDetailDTO sumServiceIncomeByShop(Long shopId, String beginDate, String endDate) {
        OrderInfoCondition condition = new OrderInfoCondition();
        condition.setShopId(shopId);
        condition.setStatusList(Collections.singletonList(OrderStatusEnum.$40.getCode()));
        condition.setEndTimeFrom(beginDate);
        condition.setEndTimeTo(endDate);
        List<OrderInfo> orderInfos = orderService.orderList(condition);
        return sumServiceIncome(orderInfos, beginDate, endDate, true);
    }

    /**
     * 项目收入
     * 加单数据
     *
     * @return
     */
    public MassagistFinanceDetailDTO sumServiceIncome(Long massagistId, String beginDate, String endDate, Boolean queryProfit) {
        OrderInfoCondition condition = new OrderInfoCondition();
        condition.setMassagistId(massagistId);
        condition.setStatusList(Collections.singletonList(OrderStatusEnum.$40.getCode()));
        condition.setEndTimeFrom(beginDate);
        condition.setEndTimeTo(endDate);
        List<OrderInfo> orderInfos = orderService.orderList(condition);
        return sumServiceIncome(orderInfos, beginDate, endDate, queryProfit);
    }

    public MassagistFinanceDetailDTO sumServiceIncome(List<OrderInfo> orderInfos, String beginDate, String endDate, Boolean queryProfit) {
        MassagistFinanceDetailDTO financeDetailDTO = new MassagistFinanceDetailDTO();
        if (CollUtil.isNotEmpty(orderInfos)) {
            //加单数据
            List<OrderExt> orderExts = orderInfos.stream().map(OrderInfo::getOrderExtList).filter(CollectionUtil::isNotEmpty).flatMap(Collection::stream).toList();
            Integer extraIncome = orderExts.stream().map(OrderExt::getOrderPrice).filter(ObjectUtil::isNotNull).reduce(0, Integer::sum);
            //当期业绩
            financeDetailDTO.setCurrentPerf(orderInfos.stream().map(OrderInfo::getOrderPrice).filter(ObjectUtil::isNotNull).reduce(0, Integer::sum) + extraIncome);
            //加单占比
            financeDetailDTO.setExtraCount(orderExts.size());
            financeDetailDTO.setExtraRatio(NumberUtil.mul(NumberUtil.div(orderExts.size(), orderInfos.size(), 2), 100));
            //车费
            Integer taxiIncome = orderInfos.stream().map(OrderInfo::getTravelPrice).filter(ObjectUtil::isNotNull).reduce(0, Integer::sum);
            financeDetailDTO.setTaxiIncome(taxiIncome);
            if (Boolean.TRUE.equals(queryProfit)) {
                List<Long> orders = new ArrayList<>(orderInfos.stream().map(OrderInfo::getId).toList());
                orders.addAll(orderExts.stream().filter(ObjectUtil::isNotNull).map(OrderExt::getId).toList());
                if (CollUtil.isNotEmpty(orders)) {
                    List<Profit> profits = profitService.queryProfitByOrderIds(orders, beginDate, endDate);
                    if (CollUtil.isNotEmpty(profits)) {
                        //月统计数据
                        Integer massagistMonthIncome = profits.stream().filter(profit -> ObjectUtil.isNotNull(profit.getOrderType()) && profit.getOrderType().equals(0)).mapToInt(profit -> ObjectUtil.defaultIfNull(profit.getMassagistIncome(), 0)).sum();
                        financeDetailDTO.setMassagistMonthIncome(massagistMonthIncome);
                        //项目收入
                        Integer massagistIncome = profits.stream().filter(profit -> ObjectUtil.isNotNull(profit.getOrderType()) && profit.getOrderType().equals(1)).mapToInt(profit -> ObjectUtil.defaultIfNull(profit.getMassagistIncome(), 0)).sum();
                        financeDetailDTO.setServiceIncome(massagistIncome);
                        //加钟收入
                        Integer massagistExtsIncome = profits.stream().filter(profit -> ObjectUtil.isNotNull(profit.getOrderType()) && profit.getOrderType().equals(2)).mapToInt(profit -> ObjectUtil.defaultIfNull(profit.getMassagistIncome(), 0)).sum();
                        financeDetailDTO.setExtraIncome(massagistExtsIncome);
                        //技师当期收入
                        financeDetailDTO.setCurrentIncome(massagistIncome + taxiIncome + massagistExtsIncome + massagistMonthIncome);
                        //月统计数据
                        Integer shopMonthIncome = profits.stream().filter(profit -> ObjectUtil.isNotNull(profit.getOrderType()) && profit.getOrderType().equals(0)).mapToInt(profit -> ObjectUtil.defaultIfNull(profit.getShopIncome(), 0)).sum();
                        financeDetailDTO.setShopMonthIncome(shopMonthIncome);
                        //项目收入
                        Integer shopIncome = profits.stream().filter(profit -> ObjectUtil.isNotNull(profit.getOrderType()) && profit.getOrderType().equals(1)).mapToInt(profit -> ObjectUtil.defaultIfNull(profit.getShopIncome(), 0)).sum();
                        financeDetailDTO.setShopServiceIncome(shopIncome);
                        //加钟收入
                        Integer shopExtsIncome = profits.stream().filter(profit -> ObjectUtil.isNotNull(profit.getOrderType()) && profit.getOrderType().equals(2)).mapToInt(profit -> ObjectUtil.defaultIfNull(profit.getShopIncome(), 0)).sum();
                        financeDetailDTO.setShopExtraIncome(shopExtsIncome);
                        //门店当期收入
                        financeDetailDTO.setShopCurrentIncome(shopIncome + shopExtsIncome + shopMonthIncome);
                    }
                }
            }
        }
        return financeDetailDTO;
    }

    /**
     * 校验手机号是否存在
     *
     * @author: lig
     * @date: 2024/1/19
     */
    public boolean validatePhoneExist(String phone) {

        MassagistCondition condition = new MassagistCondition();
        condition.setPhone(phone);
        MassagistPO po = massagistRepositoryService.getOneByCondition(condition);
        if (BeanUtil.isNotEmpty(po)) {
            return true;
        }
        return false;
    }

    /********************************************************* 华丽的分割线  ****************************************************************************/

    public MassagistIncomeDetailDTO getMassagistIncomeDetailDTO(Long massagistId, String beginDate, String endDate) {
        List<OrderInfo> orderInfos = getOverOrderList(massagistId, beginDate, endDate);
        List<Profit> profits = profitService.queryProfitByMassagistId(massagistId, beginDate, endDate);
        MassagistIncomeDetailDTO massagistIncomeDetailDTO = new MassagistIncomeDetailDTO();
        getPerformance4Massagist(orderInfos, massagistIncomeDetailDTO);
        getIncome4Massagist(profits, massagistIncomeDetailDTO);
        return massagistIncomeDetailDTO;
    }

    /**
     * 计算技师的业绩
     * 已完成订单实际支付金额(包含加钟费用) + 已取消订单(用户原因)扣除的出行费用
     *
     * @return
     */
    public void getPerformance4Massagist(List<OrderInfo> orderInfos, MassagistIncomeDetailDTO massagistIncomeDetailDTO) {
        int performance = 0;
        if (CollUtil.isNotEmpty(orderInfos)) {
            //已完成订单
            List<OrderInfo> complete = orderInfos.stream().filter(orderInfo -> Objects.equals(orderInfo.getStatus(), OrderStatusEnum.$40.getCode())).toList();
            List<OrderInfo> cancel0 = orderInfos.stream().filter(orderInfo -> Objects.equals(orderInfo.getStatus(), OrderStatusEnum.$99.getCode())).toList();
            massagistIncomeDetailDTO.setCancelCount(cancel0.size());
            //已取消订单（技师已出发或已到达）
            List<OrderInfo> cancel = orderInfos.stream().filter(orderInfo -> Objects.equals(orderInfo.getStatus(), OrderStatusEnum.$99.getCode())
                    && (Objects.equals(orderInfo.getOrderOperStatus(), OrderOperStatusEnum.$20.getCode())
                    || Objects.equals(orderInfo.getOrderOperStatus(), OrderOperStatusEnum.$30.getCode()))).toList();
            if (CollUtil.isNotEmpty(complete)) {
                OrderInfo.OrderExtCount massagistCount = OrderInfo.gainOrderExtCount(orderInfos);
                Integer extraIncome = massagistCount.getMoney();
                //已完成订单实际支付金额
                Integer income = complete.stream().map(OrderInfo::getOrderPrice).filter(ObjectUtil::isNotNull).reduce(0, Integer::sum);
                performance += extraIncome;
                performance += income;
                massagistIncomeDetailDTO.setExtraCount(massagistCount.getCount());
                massagistIncomeDetailDTO.setExtraRatio(massagistCount.getRatio());
                massagistIncomeDetailDTO.setOrderCount(complete.size());
            }
            if (CollUtil.isNotEmpty(cancel)) {
                //已取消订单(用户原因)扣除的出行费用
                Integer travelIncome = cancel.stream().map(OrderInfo::getTravelPrice).filter(ObjectUtil::isNotNull).reduce(0, Integer::sum);
                performance += travelIncome;
            }
            massagistIncomeDetailDTO.setCurrentPerf(performance);
        }
    }

    /**
     * 计算技师的收入
     *
     * @return
     */
    public void getIncome4Massagist(List<Profit> profits, MassagistIncomeDetailDTO massagistIncomeDetailDTO) {
        int income = 0;
        if (CollUtil.isNotEmpty(profits)) {
            //月补偿分润
            int massagistMonthIncome = profits.stream().filter(profit -> ObjectUtil.isNotNull(profit.getOrderType()) && profit.getOrderType().equals(0))
                    .mapToInt(profit -> ObjectUtil.defaultIfNull(profit.getMassagistIncome(), 0)).sum();
            //项目收入
            int massagistIncome = profits.stream().filter(profit -> ObjectUtil.isNotNull(profit.getOrderType()) && profit.getOrderType().equals(1))
                    .mapToInt(profit -> ObjectUtil.defaultIfNull(profit.getMassagistIncome(), 0)).sum();
            //加钟收入
            int massagistExtsIncome = profits.stream().filter(profit -> ObjectUtil.isNotNull(profit.getOrderType()) && profit.getOrderType().equals(2))
                    .mapToInt(profit -> ObjectUtil.defaultIfNull(profit.getMassagistIncome(), 0)).sum();
            //取消订单的车费
            int travelIncome = profits.stream().filter(profit -> ObjectUtil.isNotNull(profit.getOrderType()) && profit.getOrderType().equals(3))
                    .mapToInt(profit -> ObjectUtil.defaultIfNull(profit.getTravelPrice(), 0)).sum();
            //完成订单的车费
            int travelIncome0 = profits.stream().filter(profit -> ObjectUtil.isNotNull(profit.getOrderType()) && profit.getOrderType().equals(1))
                    .mapToInt(profit -> ObjectUtil.defaultIfNull(profit.getTravelPrice(), 0)).sum();
            income += massagistMonthIncome;
            income += massagistIncome;
            income += massagistExtsIncome;
            income += travelIncome;
            income += travelIncome0;
            massagistIncomeDetailDTO.setCurrentIncome(income);
            massagistIncomeDetailDTO.setExtraIncome(massagistExtsIncome);
            massagistIncomeDetailDTO.setServiceIncome(massagistIncome);
            massagistIncomeDetailDTO.setTaxiIncome(travelIncome0 + travelIncome);
        }
    }

    /**
     * 查询出技师在指定时间内的订单
     *
     * @param massagistId
     * @param beginDate
     * @return
     */
    public List<OrderInfo> getOverOrderList(long massagistId, String beginDate, String endDate) {
        OrderInfoCondition condition = new OrderInfoCondition();
        condition.setMassagistId(massagistId);
        condition.setBeginSettlementTime(beginDate);
        condition.setEndSettlementTime(endDate);
        return orderService.orderList(condition);
    }

    /**
     * 查询出技师在指定时间内的订单
     *
     * @param massagistIds
     * @param beginDate
     * @param endDate
     * @return
     */
    public List<OrderInfo> getOverOrderList(List<Long> massagistIds, String beginDate, String endDate) {
        OrderInfoCondition condition = new OrderInfoCondition();
        condition.setMassgistIds(massagistIds);
        condition.setBeginSettlementTime(beginDate);
        condition.setEndSettlementTime(endDate);
        return orderService.orderList(condition);
    }

    /**
     * @description: 验证技师可用
     * @author: lig
     * @date: 2024/3/14
     */
    public boolean verifyUsable(Long massagistId) {
        MassagistPO po = massagistRepositoryService.getById(massagistId);
        if (BeanUtil.isNotEmpty(po)) {
            ShopPO shopPO = shopRepositoryService.getById(po.getShopId());
            if (BeanUtil.isNotEmpty(shopPO) && WhetherTypeEnum.$0.getCode().equals(shopPO.getIsDel())) {
                return true;
            }
        }
        return false;

    }

    /**
     * 导出所有按摩师列表。
     * 该方法不接受任何参数，它会从数据库中检索所有按摩师的信息，并将其转换为实体列表返回。
     *
     * @return List<Massagist> 返回一个包含所有按摩师信息的实体列表。
     */
    public List<Massagist> exportList(MassagitsPageQuery query) {
        return MassagistMapperStruct.INSTANCE.po2Entity4List(massagistRepositoryService.massagistPOAllList(MassagistMapperStruct.INSTANCE.pageQuery2condition(query)));
    }


    /**
     * 获取技师的好评率
     * 技师好评率=当月好评订单数/当月订单总数*100%
     *
     * @author: lig
     * @date: 2024-04-11
     */
    public Map<Long, Double> getMassagistPositiveRatio(List<Long> massagistIds, String beginDate, String endDate) {

        Map<Long, Double> resultMap = new HashMap<>();

        Map<Long, Integer> orderMap = new HashMap<>();
        Map<Long, Long> evaluateMap = new HashMap<>();

        List<OrderInfo> orderInfos = getOverOrderList(massagistIds, beginDate, endDate);
        orderInfos = orderInfos.stream().filter(f1 -> OrderStatusEnum.$40.getCode().equals(f1.getStatus())).toList();
        if (CollUtil.isNotEmpty(orderInfos)) {
            Map<Long, List<OrderInfo>> m = orderInfos.stream().collect(Collectors.groupingBy(OrderInfo::getMassagistId));
            massagistIds.stream().forEach(a1 -> {
                Integer orderSize = 0;
                if (CollUtil.isNotEmpty(m)) {
                    if (CollUtil.isNotEmpty(m.get(a1)) && m.get(a1).size() > 0) {
                        orderSize = NumberUtil.nullToZero(m.get(a1).size());
                    }
                }
                orderMap.put(a1, orderSize);
            });
        }

        MassagistEvaluateCondition massagistEvaluateCondition = new MassagistEvaluateCondition();
        massagistEvaluateCondition.setMassagistIds(massagistIds);
        massagistEvaluateCondition.setBeginTime(beginDate);
        massagistEvaluateCondition.setEndTime(endDate);
        //技师评价数量
        List<MassagistEvaluatePO> massagistEvaluatePOList = massagistEvaluateRepositoryService.listInfo(massagistEvaluateCondition);
        if (CollUtil.isNotEmpty(massagistEvaluatePOList)) {

            Map<Long, List<MassagistEvaluatePO>> m = massagistEvaluatePOList.stream().collect(Collectors.groupingBy(MassagistEvaluatePO::getMassagistId));
            massagistIds.stream().forEach(a1 -> {
                List<MassagistEvaluatePO> tempEvaluateList = m.get(a1);
                //技师好评数
                Long positiveNum = 0l;
                if (CollUtil.isNotEmpty(tempEvaluateList)) {
                    positiveNum = m.get(a1).stream().filter(me -> me.getMassagistId().equals(a1) && Convert.toInt(me.getScore(), 0) >= 4 && Convert.toInt(me.getScore(), 0) <= 5).count();
                }
                positiveNum = NumberUtil.nullToZero(positiveNum);
                evaluateMap.put(a1, positiveNum);
            });
        }

        massagistIds.stream().forEach(m1 -> {
            Integer orderNum = Convert.toInt(orderMap.get(m1), 0);
            Long positiveNum = Convert.toLong(evaluateMap.get(m1), 0l);
            Double positiveRatio = 0d;
            if (orderNum > 0) {
                positiveRatio = NumberUtil.round(NumberUtil.div(Convert.toDouble(positiveNum), Convert.toDouble(orderNum)), 2).doubleValue();
                positiveRatio = NumberUtil.nullToZero(positiveRatio);
            }
            resultMap.put(m1, positiveRatio);
        });
        return resultMap;
    }

    /**
     * 获取技师 业绩
     *
     * @author: lig
     * @date: 2024-04-02
     */
    public Integer getMassagistPerf(OrderInfo orderInfo) {

        Date date = new Date();
        String beginDate = DateUtil.beginOfMonth(date).toString(DatePattern.NORM_DATETIME_FORMAT);
        String endDate = DateUtil.endOfMonth(date).toString(DatePattern.NORM_DATETIME_FORMAT);
        List<OrderInfo> orderInfos = getOverOrderList(orderInfo.getMassagistId(), beginDate, endDate);
        ////去掉当前操作订单 否则规则计算会错误
        //orderInfos = orderInfos.stream().filter(f1 -> !f1.getId().equals(orderInfo.getId())).toList();

        MassagistIncomeDetailDTO massagistIncomeDetailDTO = new MassagistIncomeDetailDTO();
        getPerformance4Massagist(orderInfos, massagistIncomeDetailDTO);
        //技师规则 - 指标 - 业绩
        Integer perf = NumberUtil.nullToZero(massagistIncomeDetailDTO.getCurrentPerf());
        return perf;
    }

    /**
     * 获取技师 加钟率
     *
     * @author: lig
     * @date: 2024-04-02
     */
    public Double getMassagistExtraRatio(long massagistId) {
        Date date = new Date();
        String beginDate = DateUtil.beginOfMonth(date).toString(DatePattern.NORM_DATETIME_FORMAT);
        String endDate = DateUtil.endOfMonth(date).toString(DatePattern.NORM_DATETIME_FORMAT);
        List<OrderInfo> orderInfos = getOverOrderList(massagistId, beginDate, endDate);
        //技师规则 - 指标 - 加钟率
        return OrderInfo.gainOrderExtCount(orderInfos).getRatio();
    }

    /**
     * 获取技师 好评率
     *
     * @author: lig
     * @date: 2024-04-02
     */
    public Double getMassagistPositiveRatio(long massagistId) {
        Date date = new Date();
        String beginDate = DateUtil.beginOfMonth(date).toString(DatePattern.NORM_DATETIME_FORMAT);
        String endDate = DateUtil.endOfMonth(date).toString(DatePattern.NORM_DATETIME_FORMAT);
        //技师规则 - 指标 - 好评率
        Double positiveRatio = getMassagistPositiveRatio(Arrays.asList(massagistId), beginDate, endDate).get(massagistId);
        return positiveRatio;
    }

}
